package io.xiyou.account.service.impl;


import io.xiyou.account.api.IAccountInfoService;
import io.xiyou.account.dao.mapper.AccountFreezeMapper;
import io.xiyou.account.dao.mapper.AccountInfoMapper;
import io.xiyou.account.dao.model.AccountInfo;
import io.xiyou.account.service.support.HmilySupport;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Service;
import org.dromara.hmily.annotation.HmilyTCC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Objects;

/**
 * @ClassName：AccountInfoServiceImpl
 * @Author：西柚
 * @Date：2021-10-14 10:40:25
 * @Versiion：1.0
 */
@Slf4j
@Service
public class AccountInfoServiceImpl implements IAccountInfoService {

    @Autowired
    private AccountInfoMapper accountInfoMapper;
    @Autowired
    private AccountFreezeMapper accountFreezeMapper;
    @Autowired
    private HmilySupport hmilySupport;

    /**
     * 账户扣款
     * try幂等校验
     * try悬挂处理
     * 检查余额是够扣减金额
     * 扣减金额
     *
     * @param xid
     * @param userId
     * @param money
     */
    @Override
    @Transactional
    @HmilyTCC(confirmMethod = "commit", cancelMethod = "rollback")
    public void subtractAccountBalance(String xid, Long userId, BigDecimal money) {
        //获取全局事务id
        log.info("account try begin 开始执行...xid:{}", xid);
        //幂等判断 判断local_try_log表中是否有try日志记录，如果有则不再执行
        if (hmilySupport.isExistTry(xid) > 0) {
            log.info("account try 已经执行，无需重复执行,xid:{}", xid);
            return;
        }

        //try悬挂处理，如果cancel、confirm有一个已经执行了，try不再执行
        if (hmilySupport.isExistConfirm(xid) > 0 || hmilySupport.isExistCancel(xid) > 0) {
            log.info("account try悬挂处理  cancel或confirm已经执行，不允许执行try,xid:{}", xid);
            return;
        }

        // 查询账户信息
        AccountInfo accountInfo = accountInfoMapper.selectById(userId);
        if (Objects.isNull(accountInfo)) {
            throw new RuntimeException(String.format("account try 账户不存在,xid:{}", xid));
        }

        // 扣减金额
        if (accountInfoMapper.subtractAccountBalance(userId, money) <= 0) {
            // 扣减失败
            throw new RuntimeException(String.format("account try 扣减金额失败,xid:{}", xid));
        }

        // 增加冻结金额
        accountFreezeMapper.addFreezeMoney(userId, money);

        if (money.intValue() == 2) {
            throw new RuntimeException(String.format("人为制造异常,xid:{}", xid));
        }
        log.info("account try end 结束执行...xid:{}", xid);
    }

    /**
     * confirm方法
     *
     * @param xid
     * @param userId
     * @param money
     */
    @Transactional(rollbackFor = Exception.class)
    public void commit(String xid, Long userId, BigDecimal money) {
        // 转账成功、扣除冻结金额
        accountFreezeMapper.subtractFreezeMoney(userId, money);

        log.info("account confirm begin 开始执行...xid:{},userId:{},money:{}", xid, userId, money);
    }


    /**
     * cancel方法
     * cancel幂等校验
     * cancel空回滚处理
     * 增加可用余额
     *
     * @param xid
     * @param userId
     * @param money
     */
    @Transactional(rollbackFor = Exception.class)
    public void rollback(String xid, Long userId, BigDecimal money) {
        log.info("account cancel begin 开始执行...xid:{}", xid);
        //	cancel幂等校验
        if (hmilySupport.isExistCancel(xid) > 0) {
            log.info("account cancel 已经执行，无需重复执行,xid:{}", xid);
            return;
        }
        //cancel空回滚处理，如果try没有执行，cancel不允许执行
        if (hmilySupport.isExistTry(xid) <= 0) {
            log.info("account 空回滚处理，try没有执行，不允许cancel执行,xid:{}", xid);
            return;
        }

        // 增加可用余额
        accountInfoMapper.addAccountBalance(userId, money);
        // 减少冻结金额
        accountFreezeMapper.subtractFreezeMoney(userId, money);

        log.info("account cancel end 结束执行...xid:{}", xid);
    }

}
